home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PRINTER / CRAM_V32.ARJ / CRAM.C next >
Text File  |  1992-08-09  |  28KB  |  720 lines

  1. /*
  2.  *   ------------------------------------
  3.  *   C R A M   -   the ASCII file reducer
  4.  *   ------------------------------------
  5.  *
  6.  *   CRAM  -  ASCII File Reducer  - V3.2
  7.  *   Copyright (c) 1988-92  -  Dean Tutterow  -  All Rights Reserved
  8.  *   
  9.  *   What  does  it do?   It crams as  much text  as possible onto a page
  10.  *   in  reduced format.   Using  subscript characters as  the font on an
  11.  *   Epson printer,  you  can print up to 79 characters wide and 154 rows
  12.  *   long in 2 columns.   That  works  out to  5-6 pages of  text on each
  13.  *   printed  page.   In  normal use  with  files with embedded formfeeds
  14.  *   respected, you get 4 pages of text on each printed page.
  15.  *
  16.  *   CRAM also supports the HPLJ  and related printers.  Prior to release
  17.  *   V2.2, the file CRAM.DAT  would have to be  used to send the required
  18.  *   initialization and termination strings.  Version 2.2 has implemented
  19.  *   embedded HPLJ strings.  The current  functionality is to select font
  20.  *   number  1006  (6  point  font)  and  compute  the  appropriate  line
  21.  *   separation.  At  termination, font  number 1012  (12 point  font) is
  22.  *   selected and the line  separation is set to  6 lines per inch.  This
  23.  *   implementation is only an example of  what YOU can do.  I personally
  24.  *   do not use the  standard LJ fonts.  I  load three soft fonts, 1006 -
  25.  *   the 6 pt. font,  1012 - a 12  pt. default font, and  1024 - a 24 pt.
  26.  *   font.   If  you have  a  LJ  printer, change  the  initialization of
  27.  *   GLOBAL  symbol HPLJ  from 0 to  1.   Add in  YOUR initialization and
  28.  *   termination  strings  and  recompile!
  29.  *
  30.  *   CRAM  was  written  after  I  had  printed  another  of  those  LONG
  31.  *   documentation files.  I was tired of those STACKS of listings, etc.,
  32.  *   that  gathered  dust  simply  because they  were too much trouble to
  33.  *   handle  once I printed  them.   Now  the  printed listings are small
  34.  *   enough to keep in notebooks.   As a bonus, CRAM is especially useful
  35.  *   for printing program listings.  The reduced format is just the thing
  36.  *   to show program structure and the BIG picture!
  37.  *
  38.  *   While not limited to Epson printers,  it is hardcoded for my FX-86e.
  39.  *   Of course you can provide your own setup and un-setup codes for your
  40.  *   printer, and include them in a printer setup file for CRAM to use.
  41.  *
  42.  *   USAGE:
  43.  *   
  44.  *   CRAM srcfile crammedfile [/options]
  45.  *
  46.  *   where [/options] are:
  47.  *          /COLUMN=n       with 1 ≤ n ≤ 10
  48.  *          /DUAL           automatically format dual-sided pages
  49.  *          /EPSON          default printer
  50.  *          /EVEN           prints EVEN pages only
  51.  *          /FF             if <FF> encountered, align to next logical page
  52.  *          /HPLJ           select HPLJ printer
  53.  *          /LARGE          use PICA format to get 137 chars/line, EPSON only
  54.  *          /NONE           use to have CRAM function as a column program only
  55.  *          /ODD            prints ODD pages only
  56.  *          /PAGELENGTH=n   may vary printed page length from 1-154 lines
  57.  *          /SKIP=n         number of columns to ignore in srcfile
  58.  *          /TAB=n          number of columns representing a tab
  59.  *          /TEST           test the options on the srcfile, no output files
  60.  *          /WHITE=n        number of characters of whitespace on left of page
  61.  *          /WIDTH=n        width of CRAM's page, normally 160
  62.  *   
  63.  *   The  srcfile  should  be  a  valid DOS filename;  wildcards  are not
  64.  *   accepted.   You  need  only  supply  enough  to the  option  name to
  65.  *   distinguish it from the other options, for example /C=1 and /N.
  66.  *   
  67.  *   As a daily VAX user,  I  have tried to implement the straightforward
  68.  *   command-line interface that VMS affords the user.  While the srcfile
  69.  *   and crammedfile must be in that order,  the options may be spread at
  70.  *   will along the command line.
  71.  *
  72.  *   The options are much easier understood after a few practice sessions.
  73.  *   '/COLUMN=n' is  used whenever you want more or less than the standard
  74.  *   two columns on each page.   While  normally  defaulted  to two-column
  75.  *   operation, only the first 79 characters on each line (unless some are
  76.  *   /SKIP-ped) are  visible.   '/FF' respects  embedded  formfeeds in the
  77.  *   text.   Normally off, this option moves to the next logical page when
  78.  *   encountered.   The pagelength is adjustable  through  '/PAGELENGTH=n'
  79.  *   The default is 154 rows,  which allows two pages in each column since
  80.  *   most formatters place 66 lines per page.  If you want your one-column
  81.  *   printing shifted right on the page so that you have whitespace on the
  82.  *   left  side of the page,  then '/WHITE' is just the ticket.   Finally,
  83.  *   '/SKIP=n' ignores the first 'n' characters on each input line.   This
  84.  *   allows you to print 79 useful characters in each column when printing
  85.  *   formatted files  with spaces or tabs in the first 'n' columns.   It's
  86.  *   your job to try the rest.
  87.  */
  88.  
  89. #include <stdio.h>
  90. #include <stdlib.h>
  91. #include <string.h>
  92.  
  93. /*  G L O B A L   D E F I N E S  */
  94. #define byte         unsigned char
  95. #define MAX_CHAR     160
  96. #define MAX_ROWS     154
  97. #define MAX_ELEMENTS 10
  98. #define PICA         137
  99. #define ELITE        160
  100. enum    OE           { ALL,  ODD,   EVEN };
  101. enum    PR           { NONE, EPSON, HPLJ };
  102.  
  103. /*  E R R O R   C O D E S  */
  104. #define FILENAME_TROUBLE    0x101
  105. #define INVALID_OPTION      0x102
  106. #define MISSING_FILE        0x103
  107. #define INVLD_NUM_COLUMNS   0x104
  108. #define INVLD_TAB_LENGTH    0x105
  109. #define NO_DISK_SPACE       0x106
  110.  
  111. /*  S E V E R I T Y   C O D E S  */
  112. #define FATAL         "F"
  113. #define SEVERE        "S"
  114. #define WARNING       "W"
  115. #define INFORMATIONAL "I"
  116.  
  117. /*  G L O B A L   D A T A  */ 
  118. char    BUFFER[MAX_ROWS][MAX_CHAR+1];
  119. char    PRINTER_INIT[200];
  120. char    PRINTER_TERM[200];
  121. char    SOURCE[120];
  122. int     SKIP_PT     = 0;
  123. int     NUM_COLS    = 2;
  124. int     NUM_CHAR    = MAX_CHAR;
  125. int     NUM_ROWS    = MAX_ROWS;
  126. int     WHITE       = 0;
  127. int     TAB         = 8;
  128. int     DISPLAYABLE;
  129. byte    NUM_FILES   = 0;
  130. byte    FF          = 0;
  131. byte    DUAL        = 0;
  132. byte    LEFT_EDGE;
  133. byte    TEST        = 0;
  134. int     PAGE_COUNT  = 0;
  135. int     LINE_WIDTH  = 0;
  136. long    LINE_COUNT  = 0;
  137. int     FF_FOUND    = 0;
  138. enum    OE ODD_EVEN = ALL;
  139. enum    PR FORMAT   = EPSON;
  140. char    *INFILE = 0, *OUTFILE = 0;
  141. FILE    *INPUT,  *OUT_ODD, *OUT_EVN;
  142.  
  143. void    _nullcheck();
  144. void    _setenvp();
  145. void    open_files();
  146. void    format_page();
  147. void    print_copyright();
  148. void    filter_input();
  149. void    get_printer_defaults();
  150. void    parse_command_line();
  151. void    get_filenames_and_options();
  152. void    err_exit();
  153.  
  154. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  155.  
  156. int     main( argc, argv )
  157.  
  158. int     argc;
  159. char    *argv[];
  160. {
  161.         int     i, value;
  162.         char    equivalence[100], parsed[120], *elements[MAX_ELEMENTS];
  163.         char    *option, *parse_option(), *status;
  164.  
  165.         /* Tell them who I am. */
  166.         print_copyright();
  167.  
  168.         /* Parse the command line for files and switches. */
  169.         memset( equivalence, '\0', sizeof( equivalence ) );
  170.         memset( parsed, '\0', sizeof( parsed ) );
  171.         memset( SOURCE, '\0', sizeof( SOURCE ) );
  172.         strcpy( SOURCE, argv[0] );
  173.         i = '\\';
  174.         if ( ( status = strrchr( SOURCE, i ) ) == 0 )
  175.             SOURCE[0] = 0;
  176.         else
  177.             *(status+1)= 0;
  178.         for ( i = 1; i < argc; i++ ){
  179.             strcat( equivalence, argv[i] );
  180.             strcat( equivalence, " " );
  181.         };
  182.         value = MAX_ELEMENTS;
  183.         parse_command_line( equivalence, parsed, elements, &value );
  184.         get_filenames_and_options( elements, &value, &INFILE, &OUTFILE );
  185.         get_printer_defaults();
  186.  
  187.         /* Open the proper files for reading/writing. */
  188.         open_files();
  189.  
  190.         /* Send the printer setup string. */
  191.         fputs( PRINTER_INIT, OUT_ODD );
  192.         fputs( PRINTER_INIT, OUT_EVN );
  193.  
  194.         /* Read from the input file and build the output file in memory. */
  195.         format_page();
  196.  
  197.         /* Send the printer termination string and close all files. */
  198.         fputs( PRINTER_TERM, OUT_ODD );
  199.         fputs( PRINTER_TERM, OUT_EVN );
  200.         fflush( OUT_ODD );
  201.         fflush( OUT_EVN );
  202.         fclose( OUT_ODD );
  203.         fclose( OUT_EVN );
  204.         fclose( INPUT );
  205.         return( 0 );
  206. }
  207.  
  208. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  209.  
  210. void    open_files()
  211. {
  212.         int     i;
  213.         char    *name, autoname[100] = "\0";
  214.  
  215.         /* We always have an input file to open. */
  216.         INPUT  = fopen( INFILE,  "rt" );
  217.  
  218.         /* Flag any pesky filename errors. */
  219.         if ( !INPUT )
  220.             err_exit( FILENAME_TROUBLE, FATAL );
  221.  
  222.         /* If we are just testing, 'return to sender'. */
  223.         if ( TEST ) return;
  224.  
  225.         /* Figure out the proper output file(s) to open. */
  226.         if ( DUAL || ODD_EVEN != ALL ) NUM_FILES = 1;
  227.         switch ( NUM_FILES ) {
  228.             case 2 :
  229.                 OUT_ODD = OUT_EVN = fopen( OUTFILE, "wt" );
  230.                 break;
  231.             case 1 :
  232.                 if ( OUTFILE ) strcpy( autoname, OUTFILE );
  233.                 strcat( autoname, INFILE );
  234.                 i = '.';
  235.                 name = strchr( autoname, i );
  236.                 if ( ! name ) name = autoname + strlen( autoname );
  237.                 if ( DUAL ) {
  238.                     strcpy( name, ".ODD" );
  239.                     OUT_ODD = fopen( autoname, "wt" );
  240.                     strcpy( name, ".EVN" );
  241.                     OUT_EVN = fopen( autoname, "wt" );
  242.                     }
  243.                 else {
  244.                     strcpy( name, ".CRM" );
  245.                     OUT_ODD = OUT_EVN = fopen( autoname, "wt" );
  246.                 };
  247.                 break;
  248.         };
  249.  
  250.         /* Flag any pesky filename errors. */
  251.         if ( !OUT_ODD || !OUT_EVN )
  252.             err_exit( FILENAME_TROUBLE, FATAL );
  253. }
  254.  
  255. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  256.  
  257. void    format_page()
  258. {
  259.         int     i, j, x, carryover, value, lr, current_col, status;
  260.         long    position, lc, tlc;
  261.         char    *file_status, line[MAX_CHAR+20];
  262.         FILE    *output;
  263.  
  264.         carryover = lc = tlc =0;
  265.         do {
  266.             LEFT_EDGE = WHITE;
  267.             memset( BUFFER, ' ', NUM_ROWS * (MAX_CHAR+1) );
  268.             for ( i=0; i < NUM_ROWS; i++ ) BUFFER[i][NUM_CHAR] = 0;
  269.             for ( current_col=1, lr=0; current_col<=NUM_COLS; current_col++ ) {
  270.               if ( carryover ) {
  271.                 filter_input( &line[0] );
  272.                 x = strlen( line );
  273.                 if ( x > LINE_WIDTH ) LINE_WIDTH = x;
  274.                 line[DISPLAYABLE] = '\0';
  275.                 lc++;
  276.                 if ( current_col != NUM_COLS )
  277.                     strncpy( &BUFFER[0][LEFT_EDGE], &line[0], strlen( line ) );
  278.                 else
  279.                     strcpy( &BUFFER[0][LEFT_EDGE], &line[0] );
  280.               };
  281.               for ( i=carryover; i < NUM_ROWS; i++ ) {
  282.                 carryover = 0;
  283.                 position = ftell( INPUT );
  284.                 file_status = fgets( line, 159, INPUT );
  285.                 if ( file_status == NULL ) break;
  286.                 if ( strstr( &line[1], "\f" ) ) {
  287.                   for ( j = 1; line[j] != '\f'; j++ ) {};
  288.                   fseek( INPUT, (position+j), SEEK_SET );
  289.                   line[j] = '\0';
  290.                 };
  291.                 if ( line[0] == '\f' ) {
  292.                     FF_FOUND++;
  293.                     if ( lc > LINE_COUNT ) LINE_COUNT = lc;
  294.                     tlc += lc;
  295.                     lc   = 0;
  296.                     if ( FF ) {
  297.                       if ( i <= (NUM_ROWS+1)/2 )
  298.                         i = carryover = (NUM_ROWS+1)/2;
  299.                       else  {
  300.                         carryover = 1; break;
  301.                       };
  302.                     };
  303.                 };
  304.                 filter_input( &line[0] );
  305.                 x = strlen( line );
  306.                 if ( x > LINE_WIDTH ) LINE_WIDTH = x;
  307.                 line[DISPLAYABLE] = '\0';
  308.                 lc++;
  309.                 if ( current_col != NUM_COLS )
  310.                     strncpy( &BUFFER[i][LEFT_EDGE], &line[0], strlen( line ) );
  311.                 else
  312.                     strcpy( &BUFFER[i][LEFT_EDGE], &line[0] );
  313.               };
  314.               if ( i > lr ) lr = i;
  315.               if ( file_status == NULL ) break;
  316.               LEFT_EDGE  = LEFT_EDGE + DISPLAYABLE + 1;
  317.               if ( carryover > 1 ) carryover = 0;
  318.             };
  319.  
  320.             /* Write out a page buffer and get ready for next page. */
  321.             PAGE_COUNT++;
  322.             if ( TEST ) {
  323.                 if ( lc > LINE_COUNT ) LINE_COUNT = lc;
  324.                 continue;
  325.             };
  326.             if ( ( ODD_EVEN == ALL  ) ||
  327.                ( ( ODD_EVEN == ODD  ) &&  ( PAGE_COUNT & 1 ) ) ||
  328.                ( ( ODD_EVEN == EVEN ) && !( PAGE_COUNT & 1 ) ) ) {
  329.               output = ( PAGE_COUNT & 1 ) ? OUT_ODD : OUT_EVN;
  330.               for ( i=0; i < lr; i++ ) {
  331.                 j = strlen( &BUFFER[i][0] );
  332.                 if ( j )
  333.                   if ( BUFFER[i][j-1] == '\n' ) j--;
  334.                 if ( j > (NUM_CHAR-1) )  j = NUM_CHAR - 1;
  335.                 BUFFER[i][j]   = '\n';
  336.                 BUFFER[i][j+1] = '\0';
  337.                 status = fputs( &BUFFER[i][0], output );
  338.               };
  339.               if ( status == EOF ) err_exit( NO_DISK_SPACE, SEVERE );
  340.               if ( file_status != NULL ) fputs( "\xc\0", output );
  341.             };
  342.         } while ( file_status );
  343.  
  344.         if ( TEST ) {
  345.             tlc += lc;
  346.             fprintf( stderr, "\tForm Feeds ... %d\n", FF_FOUND );
  347.             fprintf( stderr, "\tPage Count ... %d\n", PAGE_COUNT );
  348.             fprintf( stderr, "\tLine Count ... %ld (maximum input page length is %ld)\n", tlc, LINE_COUNT );
  349.             fprintf( stderr, "\tLine Width ... %d (maximum %d displayable)\n", LINE_WIDTH, DISPLAYABLE );
  350.             exit( 0 );
  351.         };
  352.  
  353. }
  354.  
  355. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  356.  
  357. void    _nullcheck () {};
  358. void    _setenvp () {};
  359.  
  360.  
  361. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  362.  
  363. void    print_copyright()
  364. {
  365.         fprintf( stderr, "CRAM  -  ASCII File Reducer  -  V3.2\n" );
  366.         fprintf( stderr, "Copyright (c) 1988-92  -  Dean Tutterow  -  All Rights Reserved\n" );
  367. }
  368.  
  369. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  370.  
  371. void    filter_input( line )
  372.  
  373. char    *line;
  374. {
  375.     int     i, n;
  376.         char    newline[MAX_CHAR+20], *oldline;
  377.  
  378.     /* Clean all tabs and formfeeds from the input line. */
  379.     oldline = line;
  380.         memset( newline, '\0', sizeof( newline ) );
  381.         for ( i = 0; i <= MAX_CHAR+1; ) {
  382.           if ( *line == '\0' ) { newline[i] = '\0'; break; }
  383.           if ( *line == '\f' ) { line++; continue; }
  384.           if ( *line == '\n' ) *line = ' ';
  385.           if ( *line == '\t' ) {
  386.         n = i;
  387.             while ( n >= 0 )
  388.               n -= TAB;
  389.         n = -n;
  390.             strncpy( &newline[i], "        ", n );
  391.             i += ( n - 1 ); }
  392.           else
  393.             newline[i] = *line;
  394.       i++;
  395.           line++;
  396.         };
  397.         if ( newline[0] != 0x0D )
  398.           strcpy( oldline, &newline[SKIP_PT] );
  399.     else
  400.           strcpy( oldline, &newline[0] );
  401. }
  402.  
  403. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  404.  
  405. void    get_printer_defaults()
  406. {
  407.         char    *file_status, filename[120];
  408.         float   x;
  409.  
  410.         if ( FORMAT == NONE ) return;
  411.         strcpy( filename, SOURCE );
  412.         strcat( filename, "CRAM.DAT" );
  413.         INPUT = fopen( filename, "rt" );
  414.         if ( !INPUT ) {
  415.           switch ( FORMAT ) {
  416.  
  417.             case EPSON:
  418.                  if ( NUM_CHAR == PICA )
  419.                      strcpy( PRINTER_INIT, "\x1b\x33\xf\x1b\x53\x30\xf\0" );
  420.                  else
  421.                      strcpy( PRINTER_INIT, "\x1b\x33\xf\x1b\x53\x30\x1b\x4d\xf\0" );
  422.                  strcpy( PRINTER_TERM, "\x1b\x32\x1b\x54\x1b\x50\x12\x1a\0" );
  423.                  break;
  424.  
  425.             case HPLJ:
  426.                  /* Compute vertical scale factor for line spacing. */
  427.                  x = 48.0 / ( (NUM_ROWS+2) / 10.0 );
  428.                  sprintf( PRINTER_INIT, "\x1b(1006X\x1b&l%2.3fC", x );
  429.                  sprintf( PRINTER_TERM, "\x1b(1012X\x1b&l6D" );
  430.                  break;
  431.           };
  432.           return;
  433.         }
  434.         file_status = fgets( PRINTER_INIT, sizeof( PRINTER_INIT ), INPUT );
  435.         if ( file_status == NULL ) goto file_error;
  436.         file_status = fgets( PRINTER_TERM, sizeof( PRINTER_TERM ), INPUT );
  437.         if ( file_status == NULL ) goto file_error;
  438.         file_error:
  439.         fclose( INPUT );
  440.         return;
  441. }
  442.  
  443.  
  444. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  445.  
  446. char    *parse_option( option, output )
  447.  
  448. char    *option, **output;
  449. {
  450.         int offset;
  451.  
  452.         if ( *option != '/' ) return( 0 );
  453.         if ( !( offset = strcspn( option, "=:" ) ) ) return( 0 );
  454.         if ( offset == strlen( option ) ) return( 0 );
  455.         *output = option + offset + 1;
  456.         return( (char *)output );
  457. }
  458.  
  459. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  460.  
  461. void    parse_command_line( input, output, arrayed, number )
  462.  
  463. char    *input, *output, *arrayed[];
  464. int    *number;
  465. {
  466.     int     i, j, k, paren;
  467.         char    temp[100], *env;
  468.  
  469.         /* Get any parameters which may be in the CRAM environment variable. */
  470.         temp[0] = (int) env = 0;
  471.         env = getenv( "CRAM" );
  472.         if ( env ) {
  473.             strcpy( temp, env );
  474.             strcat( temp, " " );
  475.         };
  476.         strcat( temp, input );
  477.  
  478.         /* Convert input line to upper case */
  479.         for ( i=0; i < strlen( temp ); i++ )
  480.           (temp)[i] = toupper( (temp)[i] );
  481.  
  482.         (output)[0] = ' ';
  483.  
  484.         for ( i=k=paren=0, j=1;( i < strlen( temp ) && k <= *number ); i++ ) {
  485.           switch ( (temp)[i] ) {
  486.             case ','  : if ( paren ) { (output)[j] = (temp)[i]; break; }
  487.             case ' '  :
  488.             case '\t' : if ( (output)[j-1]!=' ' ) (output)[j]   = ' '; break;
  489.             case '/'  : if ( (output)[j-1]!=' ' ) (output)[j++] = ' '; paren--;
  490.             case '('  : paren += 2;
  491.             case ')'  : paren--;
  492.             default   : (output)[j] = (temp)[i];
  493.       }
  494.       j++;
  495.  
  496.           /*
  497.           ** If this is the start of an argument, then place its address
  498.           ** in the argument list & null-terminate the previous argument.
  499.           */
  500.           if ( (output)[j-1] != ' ' && (output)[j-2] == ' ' ) {
  501.             if ( k != *number ) {
  502.               (arrayed)[k] = &(output)[j-1];
  503.           k++; 
  504.             };
  505.             (output)[j-2] = '\0';
  506.           };
  507.         };
  508.         (output)[j] = '\0';
  509.     *number = k;
  510. };
  511.  
  512. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  513.  
  514. void    get_filenames_and_options( elements, value, INFILE, OUTFILE )
  515.  
  516. char    **INFILE, **OUTFILE, *elements[];
  517. int    *value;
  518. {
  519.     int    first, i;
  520.         char    *status, *option, *parse_option(), first_char;
  521.  
  522.         for ( i = 0, first = 1; i < *value; i++ ) {
  523.           if ( *elements[i] != '/' ) {
  524.             if ( first ) { *INFILE = elements[i]; first = 0; }
  525.         else *OUTFILE = elements[i];
  526.         NUM_FILES++; }
  527.       else {
  528.             first_char = *(elements[i] + 1);
  529.             switch ( first_char ) {
  530.  
  531.                 case 'C' :      /* # OF COLUMNS PARAMETER */
  532.                         status = parse_option( elements[i], &option );
  533.                         if ( status ) sscanf( option, "%d", &NUM_COLS );
  534.                         else NUM_COLS = 2;
  535.                         if ( NUM_COLS > 10  || NUM_COLS < 1 )
  536.                             err_exit( INVLD_NUM_COLUMNS, FATAL );
  537.             break;
  538.  
  539.                 case 'D' :      /* DUAL - PRINT ODD/EVEN PAGES */
  540.                         DUAL = 1;
  541.                         ODD_EVEN = ALL;
  542.                         break;
  543.  
  544.                 case 'E' :
  545.                         first_char = *(elements[i] + 2);
  546.                         switch ( first_char ) {
  547.                             case 'P':   /* EPSON PRINTER */
  548.                                   FORMAT = EPSON;
  549.                                   break;
  550.  
  551.                             case 'V':   /* PRINT EVEN PAGES ONLY */
  552.                                   if ( ! DUAL ) ODD_EVEN = EVEN;
  553.                                   break;
  554.                         };
  555.                         break;
  556.  
  557.                 case 'F' :      /* RECOGNIZE FORMFEEDS */
  558.             FF = 1;
  559.             break;
  560.  
  561.                 case 'H' :      /* HPLJ PRINTER */
  562.                         FORMAT   = HPLJ;
  563.                         NUM_CHAR = MAX_CHAR;
  564.                         break;
  565.  
  566.                 case 'L' :      /* LARGE-SMALL PRINT( CHARS/LINE = 137 )*/
  567.                         if ( FORMAT == EPSON ) NUM_CHAR = PICA;
  568.                         break;
  569.  
  570.                 case 'N' :      /* NO PRINTER FORMATTING */
  571.                         FORMAT = NONE;
  572.             break;
  573.  
  574.                 case 'O' :      /* PRINT ODD PAGES ONLY */
  575.                         if ( ! DUAL ) ODD_EVEN = ODD;
  576.             break;
  577.  
  578.                 case 'P' :      /* LINES-PER-PAGE PARAMETER */
  579.                         status = parse_option( elements[i], &option );
  580.                         if ( status ) sscanf( option, "%d", &NUM_ROWS );
  581.             else NUM_ROWS = MAX_ROWS;
  582.                         if ( NUM_ROWS > MAX_ROWS ) NUM_ROWS = MAX_ROWS;
  583.                         break;
  584.  
  585.         case 'S' :    /* START INPUT PROCESSING AT THIS POSITON */
  586.                         status = parse_option( elements[i], &option );
  587.                         if ( status ) sscanf( option, "%d", &SKIP_PT );
  588.             else SKIP_PT = 0;
  589.             break;
  590.  
  591.                 case 'T' :
  592.                         first_char = *(elements[i] + 2);
  593.                         switch ( first_char ) {
  594.                             case 'A':   /* TAB INCREMENT */
  595.                                 status = parse_option( elements[i], &option );
  596.                                 if ( status ) sscanf( option, "%d", &TAB );
  597.                                 else TAB = 8;
  598.                                 if ( TAB > 8 || TAB < 1 ) {
  599.                                     err_exit( INVLD_TAB_LENGTH, WARNING );
  600.                                     TAB = 8;
  601.                                 };
  602.                                 break;
  603.  
  604.                             case 'E' :  /* TEST SOURCE FILE */
  605.                                 TEST = 1;
  606.                                 break;
  607.                         };
  608.                         break;
  609.  
  610.                 case 'W' :      
  611.                         first_char = *(elements[i] + 2);
  612.                         switch ( first_char ) {
  613.                             case 'H':   /* WHITE SPACE ON LEFT */
  614.                                 status = parse_option( elements[i], &option );
  615.                                 if ( status ) sscanf( option, "%d", &WHITE );
  616.                                 else WHITE = 35;
  617.                                 if ( WHITE > MAX_CHAR/2 ) WHITE = 35;
  618.                                 break;
  619.  
  620.                             case 'I':   /* WIDTH OF PAGE */
  621.                                 status = parse_option( elements[i], &option );
  622.                                 if ( status ) sscanf( option, "%d", &NUM_CHAR );
  623.                                 else NUM_CHAR = MAX_CHAR;
  624.                                 if ( NUM_CHAR > MAX_CHAR ) NUM_CHAR = MAX_CHAR;
  625.                                 break;
  626.                         };
  627.                         break;
  628.  
  629.                 default : 
  630.                         err_exit( INVALID_OPTION, WARNING );
  631.             };
  632.           };
  633.         };
  634.  
  635.         /* Compute the maximum displayable portion of the input line. */
  636.         DISPLAYABLE = ( NUM_CHAR - NUM_COLS + 1 - WHITE ) / NUM_COLS;
  637. }
  638.  
  639. /* /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ */
  640.  
  641. void    err_exit( code, severity )
  642.  
  643. int    code;
  644. char    *severity;
  645. {
  646.     char     err_code[20], msg[50];
  647.  
  648.     /* Display an error message, delete output file, exit. */
  649.         switch ( code ) {
  650.  
  651.       case FILENAME_TROUBLE :
  652.                strcpy( msg, "Trouble opening files, please check filenames." );
  653.                strcpy( err_code, "FILEOPEN" );
  654.                break;
  655.  
  656.       case MISSING_FILE :
  657.                strcpy( msg, "You must specify an input and output file." );
  658.                strcpy( err_code, "MISSFILE" );
  659.                break;
  660.  
  661.       case INVALID_OPTION :
  662.                strcpy( msg, "You have specified an invalid option." );
  663.                strcpy( err_code, "INVLDOPT" );
  664.                break;
  665.  
  666.           case INVLD_NUM_COLUMNS :
  667.                strcpy( msg, "You have specified an invalid number of columns." );
  668.                strcpy( err_code, "IVLDCOLS" );
  669.                break;
  670.  
  671.           case INVLD_TAB_LENGTH :
  672.                strcpy( msg, "Tab length must be between 1 and 8 characters." );
  673.                strcpy( err_code, "IVLDTAB" );
  674.                break;
  675.  
  676.           case NO_DISK_SPACE :
  677.                strcpy( msg, "Not enough disk space for output file(s)." );
  678.                strcpy( err_code, "NODSKSPC" );
  679.                break;
  680.  
  681.           default : 
  682.                strcpy( msg, "Unknown error!" );
  683.                strcpy( err_code, "UNKNOWN" );
  684.         };
  685.  
  686.         fprintf( stderr, "\nCRAM-%c-%s, %s\n", *severity, err_code, msg );
  687.  
  688.         if ( *severity == 'F' ) {
  689.           fprintf( stderr, "\n  usage: CRAM infile outfile [options]\n\n" );
  690.           fprintf( stderr, "  where [options] and defaults are:\n" );
  691.           fprintf( stderr, "\t[/column=N]      2, 1 <= N <= 10\n" );
  692.           fprintf( stderr, "\t[/dual]          off, on automatically formats dual-sided pages\n" );
  693.           fprintf( stderr, "\t[/epson]         EPSON, default printer\n" );
  694.           fprintf( stderr, "\t[/even]          off, on prints even pages only\n" );
  695.           fprintf( stderr, "\t[/ff]            off, on recognizes form feeds\n" );
  696.           fprintf( stderr, "\t[/hplj]          off, on selects HPLJ printer\n" );
  697.           fprintf( stderr, "\t[/large]         off, on selects large EPSON print\n" );
  698.           fprintf( stderr, "\t[/none]          off, on selects no printer formatting\n" );
  699.           fprintf( stderr, "\t[/odd]           off, on prints odd pages only\n" );
  700.           fprintf( stderr, "\t[/pagelength=N]  154, 1 <= pagelength <= 154\n" );
  701.           fprintf( stderr, "\t[/skip=N]        0, # of chars to skip on each input line\n" );
  702.           fprintf( stderr, "\t[/tab=N]         8, # of chars representing a tab\n" );
  703.           fprintf( stderr, "\t[/test]          test the options on the srcfile\n" );
  704.           fprintf( stderr, "\t[/white=N]       0, # of chars of white space to add to output line\n" );
  705.         };
  706.  
  707.         /* Close streams and delete partial output for TERMINAL failures. */
  708.         if ( ( *severity == 'F' ) || ( *severity == 'S' ) ) {
  709.           fflush( OUT_ODD );
  710.           fflush( OUT_EVN );
  711.           fclose( INPUT   );
  712.           fclose( OUT_ODD );
  713.           fclose( OUT_EVN );
  714.           unlink( OUTFILE );
  715.     
  716.       /* Exit with errorlevel 1 */
  717.           exit( 1 );
  718.         };
  719. }
  720.